package com.xuanyue.db.xuan.core.table.sort;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.xuanyue.db.xuan.core.table.IBitIndex;
import com.xuanyue.db.xuan.core.table.ISortElement;

public class LimitHandlerV2 {
	private static Logger log = LoggerFactory.getLogger(LimitHandlerV2.class);
	private IBitIndex where_result;
	
	private IBitIndex cache;
	private IBitIndex now;
	private IBitIndex offsetBit;
	private List<ISortElement> sl;
	
	private int offset;
	private int num;
	
	public LimitHandlerV2(int offset,int num,IBitIndex where_result) {
		this.offset = offset;
		this.num = num;
		this.where_result = where_result;
	}

	public LimitHandlerV2(int offset,int num,List<ISortElement> sl,IBitIndex where_result,IBitIndex cache,IBitIndex now,IBitIndex offsetBit) {
		this.where_result = where_result;
		this.offsetBit = offsetBit;
		this.now = now;
		this.cache = cache;
		this.num = num;
		this.offset = offset;
		this.sl = sl;
	}
	
	private void getNumber(int num,IBitIndex now,IBitIndex result) {
		now.copyFrom(where_result);
		result.setAll(false);
		ISortElement se = null;
		int nodeCount = 0;
		int i=0,s=sl.size();
		for(;i<s;i++) {//左子树优先遍历
			se = sl.get(i);
			if(se.isDesc()) {
				nodeCount = now.andByCardinality(se.getData());
			}else {
				nodeCount = now.andNotByCardinality(se.getData());
			}
			log.info(String.format("tree deep %s-->>%s  left:%s", i,num,nodeCount));
			if(num<nodeCount) {//左节点数大于offset
				// 向左走一步
				if(se.isDesc()) {
					now.and(se.getData());
				}else {
					now.andNot(se.getData());
				}
			}else {//左节点数小于offset
				//1、记录左子树
				num-=nodeCount;
				if(se.isDesc()) {
					result.orByinnerAnd(now, se.getData());
				}else {
					result.orByinnerAndNot(now, se.getData());
				}
				if(num==0) {
					return;
				}
				//2向右走一步
				if(se.isDesc()) {
					now.andNot(se.getData());
				}else {
					now.and(se.getData());
				}
			}
		}
		now.clearAllBySkipNumTrue(num);
		result.or(now);
	}

	public List<Integer> limit(float thresh) {
		int num=(int)((thresh+1)*this.num);
		if(sl==null) {
			return where_result.limit(offset, num);
		}else {
			getNumber(offset, now, offsetBit);
			getNumber(offset+num, now, cache);
			cache.andNot(offsetBit);
			return cache.getIndexOftrue();
		}
	}

	public List<Integer> limit(){
		return this.limit(0);
	}
}
